using System.Collections.Generic;
using Commons.Models.OperationsContext;
using Commons.Models.TradeValues;

namespace Commons.Services.TradeValues
{
	public class TradeService : ITradeService
	{
		public ICostProcessor CostProcessor { protected get; set; }
		public IRewardProcessor RewardProcessor { protected get; set; }

		public IEnumerable<CostStatus> GetCostsStatus(ITradeValue value, IOperationContext context, int quantity = 1)
		{
			if (value != null)
			{
				return CostProcessor.GetCostsStatus(value, context, quantity);
			}
			else
			{
				return new List<CostStatus>();
			}
		}

		public IEnumerable<ITradeValue> GetCostValues(ITradeValue value, IOperationContext context, int quantity = 1)
		{
			List<ITradeValue> values = new List<ITradeValue>();
			if (value != null)
			{
				for (int i = 0; i < quantity; i++)
				{
					values.AddRange(CostProcessor.PreProcessCost(value, context));
				}
			}
			return values;
		}

		public IEnumerable<ITradeValue> ProcessCost(ITradeValue value, IOperationContext context, int quantity = 1)
		{
			if (value != null)
			{
				IEnumerable<ITradeValue> result = CostProcessor.ProcessCost(value, context, quantity);
				if (context != null && context is BasicOperationContext)
				{
					BasicOperationContext bcontext = context as BasicOperationContext;
					if (bcontext.ContainsKey(BasicOperationContext.ProcessCostKey))
					{
						IEnumerable<ITradeValue> oldList = bcontext.Get(BasicOperationContext.ProcessCostKey) as IEnumerable<ITradeValue>;
						List<ITradeValue> list = new List<ITradeValue>(oldList);
						list.AddRange(result);
						bcontext.Add(BasicOperationContext.ProcessCostKey, list);
					}
					else
					{
						bcontext.Add(BasicOperationContext.ProcessCostKey, result);
					}
				}
				return result;
			}
			else
			{
				return new List<ITradeValue>();
			}
		}

		public IEnumerable<ITradeValue> GetRewardValues(ITradeValue value, IOperationContext context, int quantity = 1)
		{
			List<ITradeValue> values = new List<ITradeValue>();
			if (value != null)
			{
				for (int i = 0; i < quantity; i++)
				{
					values.AddRange(RewardProcessor.PreProcessReward(value, context));
				}
			}
			return values;
		}

		public IEnumerable<ITradeValue> ProcessReward(ITradeValue value, IOperationContext context, int quantity = 1)
		{
			if (value != null)
			{
				IEnumerable<ITradeValue> result = RewardProcessor.ProcessReward(value, context, quantity);
				if (context != null && context is BasicOperationContext)
				{
					BasicOperationContext bcontext = context as BasicOperationContext;
					if (bcontext.ContainsKey(BasicOperationContext.ProcessRewardKey))
					{
						IEnumerable<ITradeValue> oldList = bcontext.Get(BasicOperationContext.ProcessRewardKey) as IEnumerable<ITradeValue>;
						List<ITradeValue> list = new List<ITradeValue>(oldList);
						list.AddRange(result);
						bcontext.Add(BasicOperationContext.ProcessRewardKey, list);
					}
					else
					{
						bcontext.Add(BasicOperationContext.ProcessRewardKey, result);
					}
				}
				return result;
			}
			else
			{
				return new List<ITradeValue>();
			}
		}

		public static List<T> GetTradeValuesOfType<T>(List<ITradeValue> value) where T : ITradeValue
		{
			List<T> list = new List<T>();

			foreach (TradeValue tv in value)
				list.AddRange(GetTradeValuesOfType<T>(tv));
		
			return list;
		}

		public static List<T> GetTradeValuesOfType<T>(ITradeValue value) where T : ITradeValue
		{
			List<T> list = new List<T>();
			if (value is T)
			{
				list.Add((T) value);
			}
			else if (value is MultipleTradeValue)
			{
				foreach (ITradeValue childValue in ((MultipleTradeValue)value).Values)
				{
					list.AddRange(GetTradeValuesOfType<T>(childValue));
				}
			}
			return list;
		}
	}
}
